﻿using System;
using System.Collections.Concurrent;
using System.Linq;

namespace UtilZ.Dotnet.Ex.ValueDescription
{
    /// <summary>
    /// 值描述管理类
    /// </summary>
    public class ValueDescriptionManagerCore
    {
        /// <summary>
        /// key:groupdId,value:group
        /// </summary>
        private readonly ConcurrentDictionary<object, IValueDescriptionGroup> _typeValueDescriptionGroupDic = new ConcurrentDictionary<object, IValueDescriptionGroup>();

        /// <summary>
        /// 构造函数
        /// </summary>
        public ValueDescriptionManagerCore()
        {

        }



        /// <summary>
        /// 注册常量或枚举值描述
        /// </summary>
        /// <typeparam name="TValueType">值类型</typeparam>
        /// <typeparam name="TObject">目标类型</typeparam>
        public void Registe<TValueType, TObject>()
        {
            Type type = typeof(TObject);
            if (this._typeValueDescriptionGroupDic.ContainsKey(type))
            {
                return;
            }

            //var group = new ObjectValueDescriptionGroup(type, type);
            var group = new ValueDescriptionGroup<TValueType>(type, type);
            if (!this._typeValueDescriptionGroupDic.TryAdd(group.GroupId, group))
            {
                throw new ArgumentException($"注册类型\"{type.FullName}\"失败");
            }
        }

        /// <summary>
        /// 注册描述组
        /// </summary>
        /// <param name="group">值描述组</param>
        public void Registe(IValueDescriptionGroup group)
        {
            if (group == null)
            {
                throw new ArgumentNullException(nameof(group));
            }

            this._typeValueDescriptionGroupDic.AddOrUpdate(group.GroupId, group, (oldKey, oldValue) => { return group; });
        }






        /// <summary>
        /// 尝试根据类型获取值描述组,存在返回true,不存在返回false
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="group">值名称映射字典集合</param>
        /// <returns>存在返回true,不存在返回false</returns>
        public bool TryGetValueDescriptionGroup<T>(out IValueDescriptionGroup group)
        {
            return this._typeValueDescriptionGroupDic.TryGetValue(typeof(T), out group);
        }

        /// <summary>
        /// 根据组标识获取值描述组,存在返回true,不存在返回false
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <param name="group">值名称映射字典集合</param>
        /// <returns>存在返回true,不存在返回false</returns>
        public bool TryGetValueDescriptionGroup(object groupId, out IValueDescriptionGroup group)
        {
            if (groupId == null)
            {
                group = null;
                return false;
            }

            return this._typeValueDescriptionGroupDic.TryGetValue(groupId, out group);
        }






        /// <summary>
        /// 根据类型移除值描述组[移除成功返回true,否则返回false]
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <returns>[移除成功返回true,否则返回false]</returns>
        public bool Remove<T>()
        {
            return RemoveById(typeof(T));
        }

        /// <summary>
        /// 根据组标识移除值描述组[移除成功返回true,否则返回false]
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <returns>[移除成功返回true,否则返回false]</returns>
        public bool RemoveById(object groupId)
        {
            IValueDescriptionGroup group;
            return this._typeValueDescriptionGroupDic.TryRemove(groupId, out group);
        }





        /// <summary>
        /// 清空值描述组
        /// </summary>
        public void Clear()
        {
            this._typeValueDescriptionGroupDic.Clear();
        }

        /// <summary>
        /// 清空指定类型值描述组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void Clear<T>()
        {
            Clear(typeof(T));
        }

        /// <summary>
        /// 清空指定组标识值描述组
        /// </summary>
        /// <param name="groupId">组标识</param>
        public void Clear(object groupId)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                group.Clear();
            }
        }






        /// <summary>
        /// 根据组标识和值获取值名称(获取成功返回值名称;失败抛出ArgumentException异常)
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="value">值</param>
        /// <returns>值名称</returns>
        public string GetNameByValue<T>(object value)
        {
            return GetNameByValue(typeof(T), value);
        }

        /// <summary>
        /// 根据组标识和值获取值名称(获取成功返回值名称;失败抛出ArgumentException异常)
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <param name="value">值</param>
        /// <returns>值名称</returns>
        public string GetNameByValue(object groupId, object value)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.GetNameByValue(value);
            }
            else
            {
                throw new ArgumentException($"组标识\"{groupId}\"未注册");
            }
        }





        /// <summary>
        /// 尝试根据组标识和值获取值名称(获取成功返回true;失败返回false)
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="value">值</param>
        /// <param name="name">值名称</param>
        /// <returns>获取成功返回true;失败返回false</returns>
        public bool TryGetNameByValue<T>(object value, out string name)
        {
            return TryGetNameByValue(typeof(T), value, out name);
        }

        /// <summary>
        /// 尝试根据组标识和值获取值名称(获取成功返回true;失败返回false)
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <param name="value">值</param>
        /// <param name="name">值名称</param>
        /// <returns>获取成功返回true;失败返回false</returns>
        public bool TryGetNameByValue(object groupId, object value, out string name)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.TryGetNameByValue(value, out name);
            }
            else
            {
                name = null;
                return false;
            }
        }






        /// <summary>
        /// 根据值获取值描述(获取成功返回值描述;失败抛出ArgumentException异常)
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="value">值</param>
        /// <returns>值描述</returns>
        public string GetDescriptionByValue<T>(object value)
        {
            return GetDescriptionByValue(typeof(T), value);
        }

        /// <summary>
        /// 根据组标识和值获取值描述(获取成功返回值描述;失败抛出ArgumentException异常)
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <param name="value">值</param>
        /// <returns>值描述</returns>
        public string GetDescriptionByValue(object groupId, object value)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.GetDescriptionByValue(value);
            }
            else
            {
                throw new ArgumentException($"组标识\"{groupId}\"未注册");
            }
        }

        /// <summary>
        /// 尝试根据值获取值描述(获取成功返回true;失败返回false)
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="value">值</param>
        /// <param name="des">值描述</param>
        /// <returns>获取成功返回true;失败返回false</returns>
        public bool TryGetDescriptionByValue<T>(object value, out string des)
        {
            return TryGetDescriptionByValue(typeof(T), value, out des);
        }

        /// <summary>
        /// 尝试根据组标识和值获取值描述(获取成功返回true;失败返回false)
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <param name="value">值</param>
        /// <param name="des">值描述</param>
        /// <returns>获取成功返回true;失败返回false</returns>
        public bool TryGetDescriptionByValue(object groupId, object value, out string des)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.TryGetDescriptionByValue(value, out des);
            }
            else
            {
                des = null;
                return false;
            }
        }






        /// <summary>
        /// 根据名称获取值(获取成功返回值描述;失败抛出ArgumentException异常)
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="name">名称</param>
        /// <returns>值</returns>
        public object GetValueByName<T>(string name)
        {
            return GetValueByName(typeof(T), name);
        }

        /// <summary>
        /// 根据名称获取值(获取成功返回值描述;失败抛出ArgumentException异常)
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <param name="name">名称</param>
        /// <returns>值</returns>
        public object GetValueByName(object groupId, string name)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.GetValueByName(name);
            }
            else
            {
                throw new ArgumentException($"组标识\"{groupId}\"未注册");
            }
        }

        /// <summary>
        /// 根据名称获取值(获取成功返回true;失败返回false)
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="name">名称</param>
        /// <param name="value">值</param>
        /// <returns>获取成功返回true;失败返回false</returns>
        public bool TryGetValueByName<T>(string name, out object value)
        {
            return TryGetValueByName(typeof(T), name, out value);
        }

        /// <summary>
        /// 根据名称获取值(获取成功返回true;失败返回false)
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <param name="name">名称</param>
        /// <param name="value">值</param>
        /// <returns>获取成功返回true;失败返回false</returns>
        public bool TryGetValueByName(object groupId, string name, out object value)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.TryGetValueByName(name, out value);
            }
            else
            {
                value = null;
                return false;
            }


        }






        /// <summary>
        /// 根据描述获取值(获取成功返回值描述;失败抛出ArgumentException异常)
        /// </summary>
        /// <typeparam des="T">目标类型</typeparam>
        /// <param des="des">描述</param>
        /// <returns>值</returns>
        public object GetValueByDescription<T>(string des)
        {
            return GetValueByDescription(typeof(T), des);
        }

        /// <summary>
        /// 根据描述获取值(获取成功返回值描述;失败抛出ArgumentException异常)
        /// </summary>
        /// <param des="groupId">组标识</param>
        /// <param des="des">描述</param>
        /// <returns>值</returns>
        public object GetValueByDescription(object groupId, string des)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.GetValueByDescription(des);
            }
            else
            {
                throw new ArgumentException($"组标识\"{groupId}\"未注册");
            }
        }

        /// <summary>
        /// 根据描述获取值(获取成功返回true;失败返回false)
        /// </summary>
        /// <typeparam des="T">目标类型</typeparam>
        /// <param des="des">描述</param>
        /// <param des="value">值</param>
        /// <returns>获取成功返回true;失败返回false</returns>
        public bool TryGetValueByDescription<T>(string des, out object value)
        {
            return TryGetValueByDescription(typeof(T), des, out value);
        }

        /// <summary>
        /// 根据描述获取值(获取成功返回true;失败返回false)
        /// </summary>
        /// <param des="groupId">组标识</param>
        /// <param des="des">描述</param>
        /// <param des="value">值</param>
        /// <returns>获取成功返回true;失败返回false</returns>
        public bool TryGetValueByDescription(object groupId, string des, out object value)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.TryGetValueByDescription(des, out value);
            }
            else
            {
                throw new ArgumentException($"组标识\"{groupId}\"未注册");
            }
        }







        /// <summary>
        /// 获取指定类型值数组
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <returns>类型所有定义常量值数组</returns>
        public T[] GetValues<T>()
        {
            return GetValues<T>(typeof(T));
        }

        /// <summary>
        /// 获取指定类型值数组
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <returns>类型所有定义常量值数组</returns>
        public T[] GetValues<T>(object groupId)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.GetValues().Select(t =>
                {
                    return (T)t;
                }).ToArray();
            }
            else
            {
                throw new ArgumentException($"组标识\"{groupId}\"未注册");
            }
        }


        /// <summary>
        /// 获取指定类型值数组
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <returns>类型所有定义常量值数组</returns>
        public object[] GetValues(object groupId)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.GetValues();
            }
            else
            {
                throw new ArgumentException($"组标识\"{groupId}\"未注册");
            }
        }






        /// <summary>
        /// 获取指定类型名称数组
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <returns>类型所有定义常量值数组</returns>
        public string[] GetNames<T>()
        {
            return GetNames(typeof(T));
        }

        /// <summary>
        /// 获取指定类型名称数组
        /// </summary>
        /// <param name="groupId">组标识</param>
        /// <returns>类型所有定义常量值数组</returns>
        public string[] GetNames(object groupId)
        {
            IValueDescriptionGroup group;
            if (this.TryGetValueDescriptionGroup(groupId, out group))
            {
                return group.GetNames();
            }
            else
            {
                throw new ArgumentException($"组标识\"{groupId}\"未注册");
            }
        }



    }
}
